package cn.eastseven.demo.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import cn.eastseven.demo.netty.common.Header;
import cn.eastseven.demo.netty.common.MessageType;
import cn.eastseven.demo.netty.common.NettyMessage;
import cn.eastseven.demo.netty.common.NettyMessageDecoder;
import cn.eastseven.demo.netty.common.NettyMessageEncoder;

@Service
public class ChatClient {

	@Autowired
	private ClientConfig config;
	
	@Autowired
	private ChatClientHandler chatClientHandler;

	@Autowired
	private LoginAuthReqHandler loginAuthReqHandler;
	
	@Autowired
	private HeartBeatReqHandler heartBeatReqHandler;
	
	EventLoopGroup group = new NioEventLoopGroup();
	
	private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
	
	private ChannelFuture channelFuture = null;
	
	public ChannelFuture getChannelFuture() {
		return channelFuture;
	}
	
	public void connect() throws Exception {
		connect(config.getPort(), config.getHost());
	}
	
	void connect(int port, String host) throws Exception {
		
		try {
			
			Bootstrap b = new Bootstrap();
			b.group(group);
			b.channel(NioSocketChannel.class);
			b.option(ChannelOption.TCP_NODELAY, true);
			b.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new NettyMessageDecoder(1024 * 1024, 4, 4, -8, 0));  
					ch.pipeline().addLast(new NettyMessageEncoder());
					ch.pipeline().addLast("loginAuthReqHandler", loginAuthReqHandler);
					ch.pipeline().addLast("heartBeatReqHandler", heartBeatReqHandler);
					
					ch.pipeline().addLast("chatClientHandler",   chatClientHandler);
				}
			});
			
			this.channelFuture = b.connect(host, port).sync();
			System.out.println("isSuccess="+this.channelFuture.isSuccess()+", isDone="+this.channelFuture.isDone());
			this.channelFuture.channel().closeFuture().sync();
		} finally {
			//group.shutdownGracefully();
			executor.execute(new Runnable() {
				public void run() {
					try {
						
						TimeUnit.SECONDS.sleep(5);
						
						try {
							connect(config.getPort(), config.getHost());
						} catch (Exception e) {
							
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}
		
	}
	
	public static void main(String[] args) throws Exception {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean.xml");
		ChatClient client = ctx.getBean(ChatClient.class);
		System.out.println(ctx);
		client.connect();
		ChannelFuture f = client.getChannelFuture();
		System.out.println("isSuccess="+f.isSuccess()+", isDone="+f.isDone()+", isCancellable="+f.isCancellable()+", isCancelled="+f.isCancelled());
		if(f.isSuccess()) {
			NettyMessage msg = new NettyMessage();
			Header header = new Header();
			header.setType(MessageType.Business_REQ);
			msg.setHeader(header);
			msg.setBody("hello world");
			
			ChannelHandlerContext _ctx = f.channel().pipeline().lastContext();
			System.out.println(_ctx);
			if(_ctx != null) {
				ChannelFuture result = _ctx.writeAndFlush(msg);
				ChatClientHandler h = result.channel().pipeline().get(ChatClientHandler.class);
				String responseMsg = h.getResposeMsg();
				System.out.println("Response Message: " + responseMsg);
			}
		}
	}

}
